#include "snakewidget.h"
#include <QPainter>
#include <QPaintEvent>
#include <QMessageBox>
#include <QtAlgorithms>

SnakeWidget::SnakeWidget(QWidget *parent) :
    QWidget(parent), cntFoods(100), lenInitSnake(10), cntWidth(100), cntHeight(100)
{
    // init map
    snakeMap = new Dot *[cntWidth];
    for (int i = 0; i < cntWidth; i++) {
        snakeMap[i] = new Dot[cntHeight];
    }

    connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));

    setFocusPolicy(Qt::StrongFocus);
    replay();
}

SnakeWidget::~SnakeWidget()
{
    for (int i = 0; i < 100; i++) {
        delete snakeMap[i];
    }
    delete snakeMap;
}

void SnakeWidget::replay()
{
    for (int i = 0; i < cntWidth; i++) {
        for (int j = 0; j < cntHeight; j++) {
            snakeMap[i][j] = Empty;
        }
    }

    for (int i = 10; i < 90; i++) {
        snakeMap[50][i] = Wall;
        snakeMap[70][i] = Wall;
    }
    while (!snakeQueue.empty()) {
        snakeQueue.pop_back();
    }
    for (int i = 0; i < lenInitSnake; i++) {
        snakeQueue.push_back(QPoint(1, 1));
    }
    for (int i = 0; i < cntFoods; i++) {
        genFood();
    }
    dir = Down;
    timer.start(100);
}

void SnakeWidget::makeFail()
{
    QMessageBox::information(this, "haha!!!", "You failed!");
    replay();
}

void SnakeWidget::genFood()
{
    while (true) {
        int x = qrand() % cntWidth;
        int y = qrand() % cntHeight;
        if (snakeMap[x][y] == Empty) {
            snakeMap[x][y] = Food;
            break;
        }
    }
}

void SnakeWidget::timeout()
{
    static int dx[] = { -1, 0, 1, 0 };
    static int dy[] = { 0, 1, 0, -1 };
    QPoint cur = snakeQueue.back();

    int x = cur.x() + dx[dir];
    int y = cur.y() + dy[dir];
    x = (x + cntWidth) % cntWidth;
    y = (y + cntHeight) % cntHeight;
    if (x < 0 || x > cntWidth || y < 0 || y > cntWidth) {
        return;
    }

    if (snakeMap[x][y] == Snake || snakeMap[x][y] == Wall) {
        makeFail();
        return;
    }

    QPoint npt(x, y);
    snakeQueue.push_back(npt);

    if (snakeMap[x][y] != Food) {
        QPoint last = snakeQueue.front();
        snakeMap[last.x()][last.y()] = Empty;
        snakeQueue.pop_front();
    } else {
        genFood();
    }
    snakeMap[x][y] = Snake;
    update();
}

void SnakeWidget::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_Down:
        if (dir == Up)
            break;
        dir = Down;
        break;
    case Qt::Key_Up:
        if (dir == Down)
            break;
        dir = Up;
        break;
    case Qt::Key_Left:
        if (dir == Right)
            break;
        dir = Left;
        break;
    case Qt::Key_Right:
        if (dir == Left)
            break;
        dir = Right;
        break;
    case Qt::Key_R:
        replay();
        break;
    default:
        break;
    }
}

void SnakeWidget::paintEvent(QPaintEvent *event)
{
    int dw = width() / cntWidth;
    int dh = height() / cntHeight;
    dw = dh = qMin(dw, dh);
    QPainter painter;
    painter.begin(this);
    for (int i = 0; i < cntWidth; i++) {
        for (int j = 0; j < cntHeight; j++) {
            if (snakeMap[i][j] == Empty) {
                painter.drawRect(dw * i, dh * j, dw, dh);
            } else if (snakeMap[i][j] == Snake) {
                painter.fillRect(dw * i, dh * j, dw, dh, QBrush(Qt::blue));
            } else if (snakeMap[i][j] == Food) {
                painter.fillRect(dw * i, dh * j, dw, dh, QBrush(Qt::red));
            } else if (snakeMap[i][j] == Wall) {
                painter.fillRect(dw * i, dh * j, dw, dh, QBrush(Qt::black));
            }
        }
    }


}
